module axi_slave(
    input clk,
    input rst,

    // AIX4 master
    output                             io_master_awready,
    input                              io_master_awvalid,
    input  [31:0]                      io_master_awaddr,
    input  [3:0]                       io_master_awid,
    input  [7:0]                       io_master_awlen,
    input  [2:0]                       io_master_awsize,
    input  [1:0]                       io_master_awburst,

    output                             io_master_wready,
    input  io_master_wvalid,
    input  [63:0]                      io_master_wdata,
    input  [7:0]                       io_master_wstrb,
    input  io_master_wlast,
    
    input                             io_master_bready,
    output                reg         io_master_bvalid,
    output [1:0]                      io_master_bresp,
    output [3:0]                      io_master_bid,

    output                            io_master_arready,
    input                             io_master_arvalid,
    input [31:0]                      io_master_araddr,
    input [3:0]                       io_master_arid,
    input [7:0]                       io_master_arlen,
    input [2:0]                       io_master_arsize,
    input [1:0]                       io_master_arburst,

    input                              io_master_rready,
    output                    reg      io_master_rvalid,
    output [1:0]                       io_master_rresp,
    output reg [63:0]                   io_master_rdata,
    output                             io_master_rlast,
    output [3:0]                       io_master_rid
);


    reg [63:0] dram [0 : 67108864/2-1];
    reg [31:0] rom  [0 : 67108863];

    reg [63:0] uart;
    reg [7:0] uart_div;

    wire is_r_rom, is_r_dram, is_r_uart;
    wire is_w_rom, is_w_dram, is_w_uart;

    initial begin
        // $readmemh("/home/guowenbo/Desktop/ysyx_210184/rtl/testvectors/hello-loader.txt", rom);
        $readmemh("/home/guowenbo/Desktop/ysyx_210184/rtl/testvectors/rtthread-loader_bin2hex.txt", rom);
        // $readmemh("/home/guowenbo/Desktop/ysyx_210184/rtl/testvectors/memtest-loader.txt", rom);
        // $readmemh("/home/guowenbo/Desktop/ysyx_210184/rtl/testvectors/add-longlong-riscv64-mycpu_bin2hex.txt", dram);
        uart = (64'd33<<40) + 64'd10;
    end

    always @(posedge clk) begin
        if(rst) begin
            io_master_rdata <= 64'b0;
            io_master_rvalid <= 1'b0;
        end
        else if(is_r_rom) begin
            io_master_rdata <= {rom[io_master_araddr[27:2]], rom[io_master_araddr[27:2]]};
            io_master_rvalid <= 1'b1;
        end
        else if(is_r_dram) begin
            io_master_rdata <= dram[{4'b0, io_master_araddr[27:3]}];
            io_master_rvalid <= 1'b1;
        end
        else if(is_r_uart) begin
            if(uart[31] && io_master_araddr[2:0] == 3'b000) io_master_rdata <= {56'b0, uart_div};
            else io_master_rdata <= uart;
            io_master_rvalid <= 1'b1;
        end
        else begin
            io_master_rdata <= 64'b0;
            io_master_rvalid <= 1'b0;
        end
    end

    assign io_master_arready = 1'b1;
    assign io_master_rresp = 2'b00;
    assign io_master_rlast = 1'b1;
    assign io_master_rid = 3'b000;

    assign is_r_rom = io_master_arvalid & (io_master_araddr >= 32'h30000000) & (io_master_araddr < 32'h80000000);
    assign is_r_dram = io_master_arvalid & (io_master_araddr >= 32'h80000000);
    assign is_r_uart = io_master_arvalid & (io_master_araddr < 32'h30000000);


    


    assign io_master_awready = 1'b1;
    assign io_master_wready = 1'b1;
    assign io_master_bid = 3'b000;
    assign io_master_bresp = 2'b00;
    

    assign is_w_rom = io_master_awvalid & (io_master_awaddr >= 32'h30000000) & (io_master_awaddr < 32'h80000000);
    assign is_w_dram = io_master_awvalid & (io_master_awaddr >= 32'h80000000);
    assign is_w_uart = io_master_awvalid & (io_master_awaddr < 32'h30000000);

    always @(posedge clk) begin
        if(rst) io_master_bvalid <= 1'b0;
        else if(io_master_awvalid) io_master_bvalid <= 1'b1;
        else io_master_bvalid <= 1'b0;
    end



    wire [63:0] strb;
    assign strb = { {8{io_master_wstrb[7]}},  {8{io_master_wstrb[6]}}, {8{io_master_wstrb[5]}}, {8{io_master_wstrb[4]}}, {8{io_master_wstrb[3]}}, {8{io_master_wstrb[2]}}, {8{io_master_wstrb[1]}}, {8{io_master_wstrb[0]}} };
    always @(posedge clk) begin
        if(is_w_dram) begin
            dram[{4'b0, io_master_awaddr[27:3]}] <= dram[{4'b0, io_master_awaddr[27:3]}] & (~strb) |  io_master_wdata & strb;
        end
        else if(is_w_uart && io_master_awaddr[2:0] == 3'b000 && uart[31]) begin
            uart_div <= io_master_wdata[7:0];
            // $write("Write div\n");
        end
        else if(is_w_uart && io_master_awaddr[2:0] == 3'b000) $write("%c", io_master_wdata[7:0]);
        else if(is_w_uart) begin
            uart <= uart & (~strb) | io_master_wdata & strb;
            // $display("Write uart ctr");
        end
        
    end


endmodule